package com.dc.flow.ext

import com.dc.flow.network.BaseResult
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*

/**
 * 以flow形式，发起请求/执行任务。不支持主动emit数据，所以只适合发射一次结果的场景
 *
 * @param dispatcher 工作线程
 * @param taskBlock 耗时任务方法
 */
fun <T> requestByFlow(
    dispatcher: CoroutineDispatcher = Dispatchers.IO,
    taskBlock: suspend () -> T
): Flow<BaseResult<T>> = flow<BaseResult<T>> {
    emit(BaseResult.Success(taskBlock()))
}.flowOn(dispatcher)
    .onStart {
        emit(BaseResult.Loading(true))
    }.onCompletion {
        emit(BaseResult.Loading(false))
    }.catch { err ->
        emit(BaseResult.Error(err))
        emit(BaseResult.Loading(false))
    }

/**
 * 以flow形式，发送请求/执行任务，支持错误重试，支持多次主动emit数据
 */
fun <T> requestByFlowMultiEmit(
    dispatcher: CoroutineDispatcher = Dispatchers.IO,
    taskBlock: suspend FlowCollector<BaseResult<T>>.() -> Unit
): Flow<BaseResult<T>> = flow {
    taskBlock()
}.flowOn(dispatcher)
    .onStart {
        emit(BaseResult.Loading(true))
    }.onCompletion {
        emit(BaseResult.Loading(false))
    }.catch { err ->
        emit(BaseResult.Error(err))
        emit(BaseResult.Loading(false))
    }


/**
 * 防抖。 一段时间内，只有一次操作会触发
 */
fun <T> Flow<T>.throttleFirst(millis: Long = 600L): Flow<T> = flow {
    var lastTime = 0L
    collect {
        val currentTime = System.currentTimeMillis()
        if (currentTime - lastTime >= millis) {
            lastTime = currentTime
            emit(it)
        }
    }
}

/**
 * flow形式的定时器（需要自己控制现场，如果有需要使用flowOn）。需要自己控制停止
 *
 * @param initDelayMilliseconds 启动延时
 * @param periodMilliseconds 时间间隔
 * @param initValue 初始值
 */
fun timerFlow(
    initDelayMilliseconds: Long = 0,
    periodMilliseconds: Long = 1000L,
    initValue: Long = 0L
) = flow {
    delay(initDelayMilliseconds)
    var count = initValue
    while (true) {
        count++
        emit(count)
        delay(periodMilliseconds)
    }
}
